<template>
  <div
    class="fa-riding-area"
    :class="{
      'is-close': !state.open,
      'is-drag-over': droppable && state.isDragOver,
      undroppable: !droppable,
      'is-empty': state.empty
    }"
    :style="{ width: `${state.width}px` }"
    @click.left="onClick"
  >
    <div
      ref="area"
      class="fa-riding-area__box"
      :style="{ height: `${viewer.state.pageSum.minHeight}px` }"
      @dragover.prevent="state.isDragOver = true"
      @dragleave.prevent="state.isDragOver = false"
      @drop="onDrop"
    >
      <div v-if="state.open && state.empty" class="fa-riding-area__mask">在这里添加骑缝章</div>

      <component
        v-for="item in state.signs"
        :is="item.component"
        :key="item.id"
        :data="item"
        :riding-closed="!state.open"
        @riding-open="state.open = true"
      />
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, computed, inject, ref, toRef, getCurrentInstance, provide } from 'vue'
import { Message } from 'element-ui'
import { ContractPage, Viewer, WidgetKind } from '@/types'
import { Widget } from '@/models'
import config from '@/config'
import { EffectLock } from '@/utils'
import emitWidgetsClick from '../widget-area/emitWidgetsClick'

/** 骑缝区域状态 */
function useState(viewer: Viewer) {
  /** 页面 */
  const Page = inject('ContractPage') as ContractPage

  /** 当前文档骑缝控件列表，不包含已完成 */
  const signs = computed(() => viewer.docRidings.filter(w => !w.isDone && w.pages.includes(Page.page.p)))

  /** 是否展开区域 */
  const open = toRef(viewer.layout, 'ridingActive')

  return reactive({
    /** 是否拖拽悬浮 */
    isDragOver: false,

    /** 是否展开区域 */
    open,

    /** 区域宽度 */
    width: computed(() => {
      const { ridingWidth } = viewer
      return open.value ? ridingWidth : config.riding.widgetDefaultWidth
    }),

    /** 当前文档 */
    doc: computed(() => viewer.state.doc),

    /** 文档列表 */
    docs: computed(() => viewer.state.docs),

    /** 所有骑缝控件 */
    ridings: computed(() => viewer.ridings),

    /** 当前页骑缝控件列表 */
    signs,

    /** 是否为空 */
    empty: computed(() => !signs.value.length)
  })
}

/** 骑缝区域 */
export default defineComponent({
  name: 'FaRidingArea',

  setup() {
    /** 合同控件 */
    const viewer = inject('Viewer') as Viewer

    /** 控件拖拽和调整大小锁 */
    const DnsLocker = inject('DnsLocker') as EffectLock

    /** 控件区域 */
    provide('Area', getCurrentInstance()?.proxy)

    /** 是否可拖入 */
    const droppable = toRef(viewer, 'droppable')

    /** 骑缝区域节点 */
    const area = ref(null as null | HTMLElement)

    /** 骑缝区域状态 */
    const state = useState(viewer)

    /** 控件是否处于坐标点上 */
    function isWidgetInPoint(widget: Widget, px: number, py: number) {
      let { x, y, displayWidth: w, h } = widget

      x = (viewer.ridingWidth - w) / 2

      const isInX = x <= px && x + w >= px
      const isInY = y <= py && y + h >= py

      return isInX && isInY
    }

    /** 拖入控件 */
    async function onDrop(e: DragEvent) {
      if (!area.value) return

      state.isDragOver = false

      let data = Widget.getWidgetTransfer(e, area.value, viewer.zoom.level)

      if (!data || !droppable.value) return

      const widget = new Widget({
        ...data,
        kind: WidgetKind.RIDING
      })

      widget.docId = state.doc.id

      if (!validWidget(widget)) return

      await viewer.beforeWidgetDrop?.(widget)

      viewer.addWidget(widget)

      viewer.$emit('widget-drop', widget)

      viewer.activeWidgetId = widget.id
    }

    /** 骑缝控件数据校验 */
    function validWidget(widget: Widget) {
      if (!widget) return false

      if (!viewer.allowedRidingTypes.includes(widget.type)) {
        const allowedTypes = viewer.allowedRidingTypes.map(type => Widget.getWidgetOption(type).name).join('、')
        Message.warning(`骑缝区域只能添加${allowedTypes}`)
        return false
      }

      return true
    }

    return {
      /** 合同控件 */
      viewer: ref(viewer),

      /** 是否可拖入 */
      droppable,

      /** 骑缝区域节点 */
      area,

      /** 骑缝区域状态 */
      state,

      /** 页面点击 */
      onClick(e: MouseEvent) {
        if (DnsLocker.locked) return

        emitWidgetsClick(e, state.signs, viewer, isWidgetInPoint)
      },

      /** 拖入控件 */
      onDrop
    }
  }
})
</script>

<style lang="scss">
$border: 1px dashed $color-primary;

.fa-riding-area {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  transition: width 0.3s linear;
  user-select: none;

  &.undroppable .fa-riding-area__box {
    border: none !important;
  }

  &.is-close {
    pointer-events: none;

    .fa-riding-area__box {
      background: transparent;
      border-color: transparent;
      border-width: 0;
    }

    .fa-widget {
      pointer-events: initial;
    }
  }

  &__box {
    position: relative;
    display: flex;
    box-sizing: border-box;
    max-height: 100%;
    /** 背景模拟折页 */
    background: #fff linear-gradient(90deg, rgba(0, 0, 0, 0.05) 0, transparent 4px);
    background-size: 20%;
    border: $border;
    transition: background 0.3s linear, border 0.3s linear;
  }

  &.is-drag-over &__box {
    background-color: mix($color-primary, #fff, 3%);
  }

  &__mask {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 0;
    display: flex;
    align-items: center;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    padding: 0 calc(50% - 0.8em);
    color: #cccfd2;
    font-size: 24px;
    line-height: 1.4;
    letter-spacing: 0;
    text-align: center;
  }
}
</style>
